#ifndef VVM_C
#define VVM_C

#include "opcodes.h"
#include "stack.c"
#include "syscalls.h"
#include "exception.h"
#include "instructions.c"
#include "init.c"

bool debugMode;


void runTimeError(char* msg)
{
	fprintf(stderr,"*** FATAL: %s ***\n\n",msg);
	fprintf(stderr,"Address: 0x%x\n",pos);
	dumpRam();
	exit(1);
}

void runCode(uint32_t address)
{
	pos = address;
	while(RAM[pos] != 0 && !terminate)
	{
		int32_t instruction_address = 0;
		unsigned char opcode, arglength;
		decodeInstruction(&opcode, &arglength);
		switch(opcode)
		{
			case BEQ:
				interpret_beq();
				break;
			case BNE:
				interpret_bne();
				break;
			case BGT:
				interpret_bgt();
				break;
			case BLT:
				interpret_blt();
				break;
			case BZ:
				interpret_bz();
				break;
			case BNZ:
				interpret_bnz();
				break;
			case BRA:
				interpret_bra();
				break;
			case BSR:
				interpret_bsr();
				break;
			case TEQ:
				interpret_teq();
				break;
			case TNE:
				interpret_tne();
				break;
			case TGT:
				interpret_tgt();
				break;
			case TLT:
				interpret_tlt();
				break;
			case TGT_S:
				interpret_tgt_s();
				break;
			case TLT_S:
				interpret_tlt_s();
				break;
			case TGT_F:
				interpret_tgt_f();
				break;
			case TLT_F:
				interpret_tlt_f();
				break;
			case BEGIN_FAULT:
				interpret_try();
				break;
			case END_FAULT:
				interpret_end_try();
				break;
			case THROW:
				interpret_throw();
				break;
			case ADD:
				interpret_add();
				break;
			case FADD:
				interpret_add_f();
				break;
			case SUB:
				interpret_sub();
				break;
			case FSUB:
				interpret_sub_f();
				break;
			case MUL:
				interpret_mul();
				break;
			case FMUL:
				interpret_mul_f();
				break;
			case MUL_S:
				interpret_mul_s();
				break;
			case DIV:
				interpret_div();
				break;
			case DIV_S:
				interpret_div_s();
				break;
			case FDIV:
				interpret_div_f();
				break;
			case MOD:
				interpret_mod();
				break;
			case SHL:
				interpret_shl();
				break;
			case SHL_S:
				interpret_shl_s();
				break;
			case SHR:
				interpret_shr();
				break;
			case SHR_S:
				interpret_shr_s();
				break;
			case BOR:
				interpret_bor();
				break;
			case XOR:
				interpret_xor();
				break;
			case AND:
				interpret_and();
				break;
			case STELEM_Q:
				interpret_stelem_q();
				break;
			case STELEM_D:
				interpret_stelem_d();
				break;
			case STELEM_W:
				interpret_stelem_w();
				break;
			case STELEM_B:
				interpret_stelem_b();
				break;
			case LDELEM_Q:
				interpret_ldelem_q();
				break;
			case LDELEM_D:
				interpret_ldelem_d();
				break;
			case LDELEM_W:
				interpret_ldelem_w();
				break;
			case LDELEM_B:
				interpret_ldelem_b();
				break;
			case DUP:
				interpret_dup(arglength);
				break;
			case PUSH:
				interpret_push(arglength);
				break;
			case SYSF:
				interpret_sysf();
				break;
			case POP:
				interpret_pop(arglength);
				break;
			case RET:
				interpret_ret();
				break;
			case LOAD:
				interpret_load(arglength);
				break;
			case STORE:
				interpret_store(arglength);
				break;
			case CONVD_B: 
				interpret_convd_b();
				break;
			case CONVB_D:
				interpret_convb_d();
				break;
			case HEAPALLOC:
				interpret_heapalloc();
				break;
			case STACKALLOC:
				interpret_stackalloc();
				break;
			case HEAPFREE:
				interpret_heapfree();
				break;
			case BRK:
				fprintf(stderr,"Break at 0x%x\n",pos);
				break;
			default:
				fprintf(stderr,"Error: Encountered invalid opcode 0x%x at 0x%x\nAborting!!!\n",opcode,pos);
				abort();
				break;
		}
	}

}

#endif
